package com.firexxx.vp.infrastructure.async;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Created by mmxu6 on 2019-08-23.
 */
@Configuration
@EnableAsync(proxyTargetClass = true)
@Slf4j
public class ThreadPoolConfigurer implements AsyncConfigurer {
    @Value("${thread.pool.core.size:0}")
    private int coreSize;

    @Value("${thread.pool.max.size:0}")
    private int maxSize;

    @Override
    public Executor getAsyncExecutor() {
        if (coreSize == 0) {
            coreSize = Runtime.getRuntime().availableProcessors();
            log.info("async thread pool core size is not config, use system runtime available processors: {}", coreSize);
        }
        if (maxSize == 0) {
            maxSize = Runtime.getRuntime().availableProcessors() * 2;
            log.info("async thread pool max size is not config, use system runtime available processors * 2: {}", maxSize);
        }

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(coreSize);
        executor.setMaxPoolSize(maxSize);
        executor.setThreadNamePrefix("Async-Executor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}
